/******************************************************************************
 * 
 * File Name	: drv_i2c.c
 *
 * Version		: V1.0
 *
 * Date		    : 
 *
 * Author		: 
 *
 * Note: this file originally from project 
 *
 *****************************************************************************/

#include <rtthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "drv_i2c.h"


I2CX_INTERRUPT_DATA i2c1_data;
I2CX_INTERRUPT_DATA i2c0_data;

rt_mutex_t i2c1_mutex = RT_NULL;
rt_mutex_t i2c0_mutex = RT_NULL;

rt_mq_t i2c1_mq;
rt_mq_t i2c0_mq;

uint32_t I2Cx[2] = {I2C0, I2C1};

/*!
    \brief      handle I2C0 event interrupt request
    \param[in]  none
    \param[out] none
    \retval     none
*/
void I2C0_EventIRQ_Handler(void)
{
	if(i2c0_data.master == I2C_MASTER_CH)
	{
		if(i2c0_data.send == 1)
		{
			if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SBSEND))
			{
				/* send slave address */
				i2c_master_addressing(I2C0, i2c0_data.addr, I2C_TRANSMITTER);
			}
			else if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND))
			{
				/*clear ADDSEND bit */
				i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND);
			}
			else if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE))
			{
				if(i2c0_data.txcount > 0)
				{
					/* the master sends a data byte */
					i2c_data_transmit(I2C0, i2c0_data.txbuf[i2c0_data.txindex++]);
					i2c0_data.txcount--;
				}
				else
				{
					/* the master sends a stop condition to I2C bus */
					i2c_stop_on_bus(I2C0);
					i2c0_data.txdone = 1;
					//rt_kprintf("i2c0 master tx done.\n");
					
					/* disable the I2C0 interrupt */
					//fixed slave can't receive 'stop'.
//					i2c_interrupt_disable(I2C0, I2C_INT_ERR);
//					i2c_interrupt_disable(I2C0, I2C_INT_EV);
//					i2c_interrupt_disable(I2C0, I2C_INT_BUF);
				}
			}
		}
		else //i2c0_data.send == 0
		{
			if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SBSEND))
			{
				/* the master sends slave address */
				i2c_master_addressing(I2C0, i2c0_data.addr, I2C_RECEIVER);
			}
			else if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND))
			{
				if((1 == i2c0_data.rxcount)||(2 == i2c0_data.rxcount))
				{
					/* clear the ACKEN before the ADDSEND is cleared */
					i2c_ack_config(I2C0, I2C_ACK_DISABLE);
					/* clear the ADDSEND bit */
					i2c_interrupt_flag_clear(I2C0,I2C_INT_FLAG_ADDSEND);
				}
				else
				{
					/* clear the ADDSEND bit */
					i2c_interrupt_flag_clear(I2C0,I2C_INT_FLAG_ADDSEND);
				}
			}
			else if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_RBNE))
			{
				if(i2c0_data.rxcount > 0)
				{
					if(3 == i2c0_data.rxcount)
					{
						/* wait until the second last data byte is received into the shift register */
						while(!i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_BTC));
						/* send a NACK for the last data byte */
						i2c_ack_config(I2C0, I2C_ACK_DISABLE);
					}
					/* read a data byte from I2C_DATA*/
					i2c0_data.rxbuf[i2c0_data.rxindex++] = i2c_data_receive(I2C0);
					i2c0_data.rxcount--;
					if(0 == i2c0_data.rxcount)
					{
						i2c_stop_on_bus(I2C0);
						i2c0_data.rxdone = 1;
						//rt_kprintf("i2c0 master rx done.\n");
						
						i2c_ack_config(I2C0, I2C_ACK_ENABLE);
						i2c_ackpos_config(I2C0, I2C_ACKPOS_CURRENT);
						i2c_interrupt_disable(I2C0, I2C_INT_ERR);
						i2c_interrupt_disable(I2C0, I2C_INT_EV);
						i2c_interrupt_disable(I2C0, I2C_INT_BUF);
					}
				}
			}//i2c_interrupt_flag_get
		}
	}
	else //i2c0_data.master == 0
	{
		//recv
		
		if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND))
		{
			/* clear the ADDSEND bit */
			i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND);
		}
		else if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_RBNE))
		{
			/* if reception data register is not empty ,I2C0 will read a data from I2C_DATA */
			i2c0_data.rxbuf[i2c0_data.rxindex++] = i2c_data_receive(I2C0);
		}
		else if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_STPDET))
		{
			//rt_kprintf("I2C0_INT_FLAG_STPDET.\n");
			
			if(i2c0_data.send == 0)
			{
				i2c0_data.rxdone = 1;
//				rt_kprintf("i2c0 slave rx done.\n");

				if(i2c0_data.rxcount <32){
						
					int result = rt_mq_send(i2c0_mq , (void *)i2c0_data.rxbuf , 128);
					if(result != RT_EOK)
					{
						if(result == -RT_EFULL)
						{
							rt_kprintf("I2C0_EventIRQ_Handler rt_mq_send ERR, rt_mq is Full! err_code = %d\n", result);
						}else{
							rt_kprintf("I2C0_EventIRQ_Handler rt_mq_send ERR, err_code = %d\n", result);
						}
					}
					
				}else{
					rt_kprintf("i2c0 slave rx data >32 bytes.\n");
				}
				i2c0_data.rxcount = 0;
				//memset((void *)i2c0_data.rxbuf, 0, 128);
				i2c0_data.rxindex = 0;
			}
			
			/* clear the STPDET bit */
			i2c_enable(I2C0);
			/* disable I2C0 interrupt */
//			i2c_interrupt_disable(I2C0, I2C_INT_ERR);
//			i2c_interrupt_disable(I2C0, I2C_INT_EV);
//			i2c_interrupt_disable(I2C0, I2C_INT_BUF);
		}
		
		//send
		
		if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND))
		{
			/* clear the ADDSEND bit */
			i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND);
		}
		else if((i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE))&&(!i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_AERR)))
		{
			/* send a data byte */
			i2c_data_transmit(I2C0, i2c0_data.txbuf[i2c0_data.txindex++]);
			
			if(i2c0_data.txcount == i2c0_data.txindex)
			{
				i2c0_data.txdone = 1;
				//i2c0_data.txindex = 0;
				//rt_kprintf("i2c0 slave tx done.\n");
			}
		}	
	}
}
/*!

    \brief      handle I2C0 error interrupt request
    \param[in]  none
    \param[out] none
    \retval     none
*/
void I2C0_ErrorIRQ_Handler(void)
{
    /* no acknowledge received */
    if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_AERR)){
		i2c0_data.status |= (1<<0);
        i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_AERR);
    }

    /* SMBus alert */
    if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SMBALT)){
		i2c0_data.status |= (1<<1);
        i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_SMBALT);
    }

    /* bus timeout in SMBus mode */
    if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SMBTO)){
		i2c0_data.status |= (1<<2);
        i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_SMBTO);
    }

    /* over-run or under-run when SCL stretch is disabled */
    if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_OUERR)){
		i2c0_data.status |= (1<<3);
        i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_OUERR);
    }

    /* arbitration lost */
    if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_LOSTARB)){
		i2c0_data.status |= (1<<4);
        i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_LOSTARB);
    }

    /* bus error */
    if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_BERR)){
		i2c0_data.status |= (1<<5);
        i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_BERR);
    }

    /* CRC value doesn't match */
    if(i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_PECERR)){
		i2c0_data.status |= (1<<6);
        i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_PECERR);
    }

    /* disable the error interrupt */
//    i2c_interrupt_disable(I2C0, I2C_INT_ERR);
//    i2c_interrupt_disable(I2C0, I2C_INT_EV);
//    i2c_interrupt_disable(I2C0, I2C_INT_BUF);
}



/*!
    \brief      handle I2C1 event interrupt request
    \param[in]  none
    \param[out] none
    \retval     none
*/
void I2C1_EventIRQ_Handler(void)
{
	if(i2c1_data.master == I2C_MASTER_CH)
	{
		if(i2c1_data.send == 1)
		{
			if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_SBSEND))
			{
				/* send slave address */
				i2c_master_addressing(I2C1, i2c1_data.addr, I2C_TRANSMITTER);
			}
			else if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_ADDSEND))
			{
				/*clear ADDSEND bit */
				i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_ADDSEND);
			}
			else if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_TBE))
			{
				if(i2c1_data.txcount > 0)
				{
					/* the master sends a data byte */
					i2c_data_transmit(I2C1, i2c1_data.txbuf[i2c1_data.txindex++]);
					i2c1_data.txcount--;
				}
				else
				{
					/* the master sends a stop condition to I2C bus */
					i2c_stop_on_bus(I2C1);
					i2c1_data.txdone = 1;
					//rt_kprintf("i2c1 master tx done.\n");
					
					/* disable the I2C1 interrupt */
					//fixed slave can't receive 'stop'.
//					i2c_interrupt_disable(I2C1, I2C_INT_ERR);
//					i2c_interrupt_disable(I2C1, I2C_INT_EV);
//					i2c_interrupt_disable(I2C1, I2C_INT_BUF);
				}
			}
		}
		else //i2c1_data.send == 0
		{
			if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_SBSEND))
			{
				/* the master sends slave address */
				i2c_master_addressing(I2C1, i2c1_data.addr, I2C_RECEIVER);
			}
			else if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_ADDSEND))
			{
				if((1 == i2c1_data.rxcount)||(2 == i2c1_data.rxcount))
				{
					/* clear the ACKEN before the ADDSEND is cleared */
					i2c_ack_config(I2C1, I2C_ACK_DISABLE);
					/* clear the ADDSEND bit */
					i2c_interrupt_flag_clear(I2C1,I2C_INT_FLAG_ADDSEND);
				}
				else
				{
					/* clear the ADDSEND bit */
					i2c_interrupt_flag_clear(I2C1,I2C_INT_FLAG_ADDSEND);
				}
			}
			else if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_RBNE))
			{
				if(i2c1_data.rxcount > 0)
				{
					if(3 == i2c1_data.rxcount)
					{
						/* wait until the second last data byte is received into the shift register */
						while(!i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_BTC));
						/* send a NACK for the last data byte */
						i2c_ack_config(I2C1, I2C_ACK_DISABLE);
					}
					/* read a data byte from I2C_DATA*/
					i2c1_data.rxbuf[i2c1_data.rxindex++] = i2c_data_receive(I2C1);
					i2c1_data.rxcount--;
					if(0 == i2c1_data.rxcount)
					{
						i2c_stop_on_bus(I2C1);
						i2c1_data.rxdone = 1;
						//rt_kprintf("i2c1 master rx done.\n");
						
						i2c_ack_config(I2C1, I2C_ACK_ENABLE);
						i2c_ackpos_config(I2C1, I2C_ACKPOS_CURRENT);
						i2c_interrupt_disable(I2C1, I2C_INT_ERR);
						i2c_interrupt_disable(I2C1, I2C_INT_EV);
						i2c_interrupt_disable(I2C1, I2C_INT_BUF);
					}
				}
			}//i2c_interrupt_flag_get
		}
	}
	else //i2c1_data.master == 0
	{
		//recv
		
		if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_ADDSEND))
		{
			/* clear the ADDSEND bit */
			i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_ADDSEND);
		}
		else if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_RBNE))
		{
			/* if reception data register is not empty ,I2C1 will read a data from I2C_DATA */
			i2c1_data.rxbuf[i2c1_data.rxindex++] = i2c_data_receive(I2C1);
		}
		else if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_STPDET))
		{
			//rt_kprintf("I2C1_INT_FLAG_STPDET.\n");
			
			if(i2c1_data.send == 0)
			{
				i2c1_data.rxdone = 1;

				if(i2c1_data.rxcount <32){
					int result = rt_mq_send(i2c1_mq , (void *)i2c1_data.rxbuf , 128);
					if(result != RT_EOK)
					{
						if(result == -RT_EFULL)
						{
							rt_kprintf("I2C1_EventIRQ_Handler rt_mq_send ERR, rt_mq is Full! err_code = %d\n", result);
						}else{
							rt_kprintf("I2C0_EventIRQ_Handler rt_mq_send ERR, err_code = %d\n", result);
						}
					}
				}else{
					rt_kprintf("i2c1 slave rx data >32 bytes.\n");
				}
				i2c1_data.rxcount = 0;
//				rt_kprintf("i2c1 slave rx done.\n");
				//memset((void *)i2c0_data.rxbuf, 0, 128);
				i2c1_data.rxindex = 0;
			}
			
			/* clear the STPDET bit */
			i2c_enable(I2C1);
			/* disable I2C1 interrupt */
//			i2c_interrupt_disable(I2C1, I2C_INT_ERR);
//			i2c_interrupt_disable(I2C1, I2C_INT_EV);
//			i2c_interrupt_disable(I2C1, I2C_INT_BUF);
		}
		
		//send
		
		if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_ADDSEND))
		{
			/* clear the ADDSEND bit */
			i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_ADDSEND);
		}
		else if((i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_TBE))&&(!i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_AERR)))
		{
			/* send a data byte */
			i2c_data_transmit(I2C1, i2c1_data.txbuf[i2c1_data.txindex++]);
			
			if(i2c1_data.txcount == i2c1_data.txindex)
			{
				i2c1_data.txdone = 1;
				//i2c1_data.txindex = 0;
				//rt_kprintf("i2c1 slave tx done.\n");
			}
		}	
	}
}

/*!
    \brief      handle I2C1 error interrupt request
    \param[in]  none
    \param[out] none
    \retval     none
*/
void I2C1_ErrorIRQ_Handler(void)
{
    /* no acknowledge received */
    if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_AERR)){
		i2c1_data.status |= (1<<0);
        i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_AERR);
    }

    /* SMBus alert */
    if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_SMBALT)){
		i2c1_data.status |= (1<<1);
        i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_SMBALT);
    }

    /* bus timeout in SMBus mode */
    if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_SMBTO)){
		i2c1_data.status |= (1<<2);
        i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_SMBTO);
    }

    /* over-run or under-run when SCL stretch is disabled */
    if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_OUERR)){
		i2c1_data.status |= (1<<3);
        i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_OUERR);
    }

    /* arbitration lost */
    if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_LOSTARB)){
		i2c1_data.status |= (1<<4);
        i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_LOSTARB);
    }

    /* bus error */
    if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_BERR)){
		i2c1_data.status |= (1<<5);
        i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_BERR);
    }

    /* CRC value doesn't match */
    if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_PECERR)){
		i2c1_data.status |= (1<<6);
        i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_PECERR);
    }

    /* disable the error interrupt */
//    i2c_interrupt_disable(I2C1, I2C_INT_ERR);
//    i2c_interrupt_disable(I2C1, I2C_INT_BUF);
//    i2c_interrupt_disable(I2C1, I2C_INT_EV);
}



/*-----------------------------------------------------------------------------
** PROC NAME	: i2c_reset_rx_data

** DESCRIPTION	: reset i2cx interrupt receive data

** PARAMETERS	: i2c_periph - I2Cx(x=0,1,2)
**                

** RETURN       : 0 - success, -1 - fail.

** NOTES:
**----------------------------------------------------------------------------*/
int i2c_reset_rx_data(uint32_t i2c_periph)
{
	I2CX_INTERRUPT_DATA *pdata;
	
	if(i2c_periph == I2C1)
	{
		pdata = &i2c1_data;
	}
	else if(i2c_periph == I2C0)
	{
		pdata = &i2c0_data;
	}
	else
	{
		rt_kprintf("i2c_periph not support. I2Cx(x=0,1,2).\n");
		return -1;
	}
	
	pdata->rxcount = 128;
	pdata->rxindex = 0;
	pdata->rxdone = 0;
	pdata->status = 0;
	
	return 0;
}

/*-----------------------------------------------------------------------------
** PROC NAME	: i2c_reset_tx_data

** DESCRIPTION	: reset i2cx interrupt transmit data

** PARAMETERS	: i2c_periph - I2Cx(x=0,1,2)
**                

** RETURN       : 0 - success, -1 - fail.

** NOTES:
**----------------------------------------------------------------------------*/
int i2c_reset_tx_data(uint32_t i2c_periph)
{
	I2CX_INTERRUPT_DATA *pdata;
	
	if(i2c_periph == I2C1)
	{
		pdata = &i2c1_data;
	}
	else if(i2c_periph == I2C0)
	{
		pdata = &i2c0_data;
	}
	else 
	{
		rt_kprintf("i2c_periph not support. I2Cx(x=0,1,2).\n");
		return -1;
	}
	
	pdata->txcount = 0;
	pdata->txindex = 0;
	pdata->txdone = 0;
	pdata->status = 0;

	return 0;
}

int i2c_init_data(uint32_t i2c_periph, uint8_t master, uint8_t slave_addr)
{
//	if(master == I2C_MASTER_CH){
//		rt_kprintf("\n I2C%d to : I2C_MASTER_CH\r\n", (i2c_periph == I2C1) ? 1 : 0);
//	}else{
//		rt_kprintf("\n I2C%d to : I2C_SLAVE_CH\r\n", (i2c_periph == I2C1) ? 1 : 0);
//	}

	/* enable the I2Cx interrupt */
    i2c_interrupt_enable(i2c_periph, I2C_INT_ERR);
    i2c_interrupt_enable(i2c_periph, I2C_INT_BUF);
    i2c_interrupt_enable(i2c_periph, I2C_INT_EV);
	
	if(i2c_periph == I2C0)
	{
		memset((void *)&i2c0_data, 0, sizeof(I2CX_INTERRUPT_DATA));
		i2c0_data.master = master;
		i2c0_data.addr = slave_addr;
		i2c0_data.send = 0;
	}
	else if(i2c_periph == I2C1)
	{
		memset((void *)&i2c1_data, 0, sizeof(I2CX_INTERRUPT_DATA));
		i2c1_data.master = master;
		i2c1_data.addr = slave_addr;
		i2c1_data.send = 0;
	}
	else
	{
		rt_kprintf("invalid i2c_periph=%08x\n", i2c_periph);
		return -1;
	}

	return 0;

}

/*-----------------------------------------------------------------------------
** PROC NAME	: i2c_init

** DESCRIPTION	: initialize i2c hardware and interrupt data

** PARAMETERS	: i2c_periph - I2Cx(x=0,1,2)
**                master - 1 master mode
**						   0 slave mode
**                slave_addr - i2cx slace address

** RETURN       : 0 - success, -1 - fail.

** NOTES:
**----------------------------------------------------------------------------*/
int i2c_init(uint32_t i2c_periph, uint8_t master, uint8_t slave_addr)
{
	if(i2c_periph == I2C0)
	{
		memset((void *)&i2c0_data, 0, sizeof(I2CX_INTERRUPT_DATA));
	
		if(i2c0_mutex == RT_NULL)
		{
			i2c0_mutex = rt_mutex_create("i2c0m", RT_IPC_FLAG_FIFO);
			if(i2c0_mutex == RT_NULL)
			{
				rt_kprintf(" create i2c0_mutex failed .\n");
				return -1;
			}
		}
		
		i2c0_data.master = master;
		i2c0_data.addr = slave_addr;
		i2c0_data.send = 0;
		
		i2c_deinit(i2c_periph);

		nvic_irq_enable(I2C0_EV_IRQn, 0, 3);
		nvic_irq_enable(I2C0_ER_IRQn, 0, 2);

		/* enable GPIOB clock */
		rcu_periph_clock_enable(RCU_GPIOB);
		/* connect PB6 to I2C0_SCL, PB7 to I2C0_SDA */
		gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
		/* connect PB5 to I2C0_SMBA*/
//		gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
		
		/* enable I2C clock */
		rcu_periph_clock_enable(RCU_I2C0);
		/* configure I2C clock */
		i2c_clock_config(i2c_periph,100000,I2C_DTCY_2);
		/* I2C address configure */
		i2c_mode_addr_config(i2c_periph, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, slave_addr);
		/* enable I2C0 */
		i2c_enable(i2c_periph);
		/* enable acknowledge */
		i2c_ack_config(i2c_periph,I2C_ACK_ENABLE);

//		IPMB_A_EN_HIGH;
		
	}
	else if(i2c_periph == I2C1)
	{
		memset((void *)&i2c1_data, 0, sizeof(I2CX_INTERRUPT_DATA));
	
		if(i2c1_mutex == RT_NULL)
		{
			i2c1_mutex = rt_mutex_create("i2c1m", RT_IPC_FLAG_FIFO);
			if(i2c1_mutex == RT_NULL)
			{
				rt_kprintf(" create i2c1_mutex failed .\n");
				return -1;
			}
		}
		
		i2c1_data.master = master;
		i2c1_data.addr = slave_addr;
		i2c1_data.send = 0;
		
		i2c_deinit(i2c_periph);
		
		nvic_irq_enable(I2C1_EV_IRQn, 0, 4);
		nvic_irq_enable(I2C1_ER_IRQn, 0, 1);
		
		
		/* enable GPIOB clock */
		rcu_periph_clock_enable(RCU_GPIOB);
		/* connect PB10 to I2C1_SCL, PB11 to I2C2_SDA */
		gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10 | GPIO_PIN_11);
		/* connect PB12 to I2C1_SMBA*/
//		gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_12);
		
		/* enable I2C clock */
		rcu_periph_clock_enable(RCU_I2C1);
		/* configure I2C clock */
		i2c_clock_config(i2c_periph,100000,I2C_DTCY_2);
		/* I2C address configure */
		i2c_mode_addr_config(i2c_periph, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, slave_addr);
		/* enable I2C1 */
		i2c_enable(i2c_periph);
		/* enable acknowledge */
		i2c_ack_config(i2c_periph,I2C_ACK_ENABLE);

//		IPMB_B_EN_HIGH;
	}
	else
	{
		rt_kprintf("invalid i2c_periph=%08x\n", i2c_periph);
		return -1;
	}
	
	return 0;
}

/*-----------------------------------------------------------------------------
** PROC NAME	: i2c_recv_thread_entry

** DESCRIPTION	: i2c slave receive data and handle

** PARAMETERS	: arg - i2c_periph I2Cx(x=0,1,2)

** RETURN       : 

** NOTES:
**----------------------------------------------------------------------------*/
void i2c_recv_thread_entry(void *arg)
{
	uint32_t i2c_periph = (uint32_t) arg;
	rt_mq_t i2c_mq = (i2c_periph == I2C1) ? i2c1_mq : i2c0_mq;
	uint8_t buf[128];
	int i;
	
	while(1)
	{
		if(rt_mq_recv(i2c_mq, &buf, sizeof(buf), RT_WAITING_FOREVER) == RT_EOK)
		{
			rt_kprintf("I2C%d recv: ", (i2c_periph == I2C1) ? 1 : 0);
			for(i=0; i<16; i++){
				rt_kprintf("%02x ", buf[i]);
			}
			rt_kprintf("\n");
			
			buf[0] = 0xf1;
			
			i2c_slave_send(i2c_periph, 0x82, buf, 10);
		}
	}
}

/*-----------------------------------------------------------------------------
** PROC NAME	: i2c_recv_start

** DESCRIPTION	: start i2c slave receive thread

** PARAMETERS	: i2c_periph - I2Cx(x=0,1,2)

** RETURN       : 0 - success, -1 - fail.

** NOTES:
**----------------------------------------------------------------------------*/
int i2c_recv_start(uint32_t i2c_periph)
{
	rt_thread_t tid;

	if(i2c_periph == I2C0)
	{
		i2c0_mq = rt_mq_create("i2c0mq", 128, 10, RT_IPC_FLAG_FIFO);
		if(i2c0_mq == RT_NULL)
		{
			rt_kprintf("rt_mq_create() failed.\n");
		}
		
		tid = rt_thread_create("i2c0_rx", i2c_recv_thread_entry, (void *)I2C0,
			1024, RT_THREAD_PRIORITY_MAX/3, 20);
		if (tid != RT_NULL)
		{
			rt_thread_startup(tid);
		}
		
		i2c_reset_rx_data(i2c_periph);	
		i2c0_data.master = I2C_SLAVE_CH;
		i2c0_data.send = 0;
		i2c0_data.rxcount = 128;
		
		/* enable the I2Cx interrupt */
		i2c_interrupt_enable(i2c_periph, I2C_INT_ERR);
		i2c_interrupt_enable(i2c_periph, I2C_INT_BUF);
		i2c_interrupt_enable(i2c_periph, I2C_INT_EV);
	}
		
	if(i2c_periph == I2C1)
	{
		i2c1_mq = rt_mq_create("i2c1mq", 128, 10, RT_IPC_FLAG_FIFO);
		if(i2c1_mq == RT_NULL)
		{
			rt_kprintf("rt_mq_create() failed.\n");
		}
		
		tid = rt_thread_create("i2c1_rx", i2c_recv_thread_entry, (void *)I2C1,
			1024, RT_THREAD_PRIORITY_MAX/3, 20);
		if (tid != RT_NULL)
		{
			rt_thread_startup(tid);
		}
		
		i2c_reset_rx_data(i2c_periph);	
		i2c1_data.master = I2C_SLAVE_CH;
		i2c1_data.send = 0;
		i2c1_data.rxcount = 128;
		
		/* enable the I2Cx interrupt */
		i2c_interrupt_enable(i2c_periph, I2C_INT_ERR);
		i2c_interrupt_enable(i2c_periph, I2C_INT_BUF);
		i2c_interrupt_enable(i2c_periph, I2C_INT_EV);
	}	

	return 0;
}


 
/*-----------------------------------------------------------------------------
** PROC NAME	: i2c_master_send

** DESCRIPTION	: send data in master transmit mode

** PARAMETERS	: i2c_periph - I2Cx(x=0,1,2)
**                slave_addr - i2cx slace address
**                buf - data to transmit
**                len - data length to transmit

** RETURN       : 0 - success, -1 - fail.

** NOTES:
**----------------------------------------------------------------------------*/
int i2c_master_send(uint32_t i2c_periph, uint8_t slave_addr, uint8_t *buf, uint32_t len)
{
	I2CX_INTERRUPT_DATA *pdata;
	int timeout = 100000;
	rt_mutex_t mutex;
	
	if(i2c_periph == I2C0)
	{
		pdata = &i2c0_data;
		mutex = i2c0_mutex;
	}
	else if(i2c_periph == I2C1)
	{
		pdata = &i2c1_data;
		mutex = i2c1_mutex;
	}
	else
	{
		rt_kprintf("i2c_periph not support. I2Cx(x=0,1,2).\n");
		return -1;
	}
	
	if(rt_mutex_take(mutex , RT_WAITING_FOREVER) != RT_EOK)
	{
		rt_kprintf("i2c_master_send() rt_mutex_take return error.\n");
		return -1;
	}
	
	i2c_reset_tx_data(i2c_periph);
	
	pdata->addr = slave_addr;
	pdata->master = I2C_MASTER_CH;
	pdata->send = 1;
	memcpy((void *)&pdata->txbuf[0], buf, len);
	pdata->txcount = len;
	
	/* enable the I2Cx interrupt */
    i2c_interrupt_enable(i2c_periph, I2C_INT_ERR);
    i2c_interrupt_enable(i2c_periph, I2C_INT_BUF);
    i2c_interrupt_enable(i2c_periph, I2C_INT_EV);
	
	/* the master waits until the I2C bus is idle */
	timeout= 1000;
    while(i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY) && (timeout--))
	{
		rt_thread_delay(1);
	}
	
	if(timeout <= 0)
	{
		rt_kprintf("i2c_master_send() timeout waits until the I2C bus is idle\n");
		rt_mutex_release(mutex);
		
//		rt_kprintf("pdata->status=%08X\n", pdata->status);
//		rt_kprintf("I2C_STAT0(I2C0)=%08X\n", I2C_STAT0(i2c_periph));
//		rt_kprintf("I2C_STAT1(I2C0)=%08X\n", I2C_STAT1(i2c_periph));
	
		i2c_stop_on_bus(i2c_periph);
		rt_thread_delay(20);
		if(i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY))
		{
			rt_kprintf("Reinit I2C%d\n", (i2c_periph == I2C1) ? 1 : 0);
			
			i2c_deinit(i2c_periph);
		
			/* configure I2C clock */
			i2c_clock_config(i2c_periph,100000,I2C_DTCY_2);
			/* I2C address configure */
			i2c_mode_addr_config(i2c_periph, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, slave_addr);
			/* enable I2C0 */
			i2c_enable(i2c_periph);
			/* enable acknowledge */
			i2c_ack_config(i2c_periph,I2C_ACK_ENABLE);
		}
		
		/* disable the error interrupt */
		i2c_interrupt_disable(i2c_periph, I2C_INT_ERR);
		i2c_interrupt_disable(i2c_periph, I2C_INT_EV);
		i2c_interrupt_disable(i2c_periph, I2C_INT_BUF);
		
		return -1;
	}

    /* the master sends a start condition to I2C bus */
    i2c_start_on_bus(i2c_periph);
	
	timeout= 200000;
	while((pdata->txdone == 0) && (pdata->status == 0) && (timeout--));
	
	if(timeout <= 0)
	{
		rt_kprintf("i2c_master_send() timeout waits until the I2C bus is send\n");
		rt_mutex_release(mutex);
		
		i2c_stop_on_bus(i2c_periph);
		/* disable the error interrupt */
		i2c_interrupt_disable(i2c_periph, I2C_INT_ERR);
		i2c_interrupt_disable(i2c_periph, I2C_INT_EV);
		i2c_interrupt_disable(i2c_periph, I2C_INT_BUF);
		
		return -1;
	}
	
	if(pdata->status != 0)
	{
		rt_kprintf("i2c_master_send() error status=%08X\n", pdata->status);
		
		i2c_stop_on_bus(i2c_periph);
		/* disable the error interrupt */
		i2c_interrupt_disable(i2c_periph, I2C_INT_ERR);
		i2c_interrupt_disable(i2c_periph, I2C_INT_EV);
		i2c_interrupt_disable(i2c_periph, I2C_INT_BUF);
		
		rt_mutex_release(mutex);
		return -1;
	}
	
	rt_mutex_release(mutex);
	return 0;
}

/*-----------------------------------------------------------------------------
** PROC NAME	: i2c_master_recv

** DESCRIPTION	: receive data in master receive mode

** PARAMETERS	: i2c_periph - I2Cx(x=0,1,2)
**                slave_addr - i2cx slace address
**                buf - data to receive
**                len - data length to receive

** RETURN       : 0 - success, -1 - fail.

** NOTES:
**----------------------------------------------------------------------------*/
int i2c_master_recv(uint32_t i2c_periph, uint8_t slave_addr, uint8_t *buf, uint32_t len)
{
	I2CX_INTERRUPT_DATA *pdata;
	int timeout = 100000;
	rt_mutex_t mutex;
	
	if(i2c_periph == I2C0)
	{
		pdata = &i2c0_data;
		mutex = i2c0_mutex;
	}
	else if(i2c_periph == I2C1)
	{
		pdata = &i2c1_data;
		mutex = i2c1_mutex;
	}
	else
	{
		rt_kprintf("i2c_periph not support. I2Cx(x=0,1,2).\n");
		return -1;
	}
	
	if(rt_mutex_take(mutex , RT_WAITING_FOREVER) != RT_EOK)
	{
		rt_kprintf("i2c_master_recv() rt_mutex_take return error.\n");
		return -1;
	}
	
	i2c_reset_rx_data(i2c_periph);
	
	pdata->addr = slave_addr;
	pdata->master = I2C_MASTER_CH;
	pdata->send = 0;
	pdata->rxcount = len;
	
	/* enable the I2Cx interrupt */
    i2c_interrupt_enable(i2c_periph, I2C_INT_ERR);
    i2c_interrupt_enable(i2c_periph, I2C_INT_BUF);
    i2c_interrupt_enable(i2c_periph, I2C_INT_EV);
	
	/* the master waits until the I2C bus is idle */
	timeout= 1000;
    while(i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY) && (timeout--))
	{
		rt_thread_delay(1);
	}
	
	if(timeout <= 0)
	{
		rt_kprintf("i2c_master_recv() timeout waits until the I2C bus is idle\n");
		rt_kprintf("i2c_master_recv() slave_addr = 0x%02x\n", slave_addr);
		rt_mutex_release(mutex);
		
		i2c_stop_on_bus(i2c_periph);
		/* disable the error interrupt */
		i2c_interrupt_disable(i2c_periph, I2C_INT_ERR);
		i2c_interrupt_disable(i2c_periph, I2C_INT_EV);
		i2c_interrupt_disable(i2c_periph, I2C_INT_BUF);
		
		return -1;
	}

    /* the master sends a start condition to I2C bus */
    i2c_start_on_bus(i2c_periph);
	
	timeout= 100000;
	while((pdata->rxdone == 0) && (pdata->status == 0) && (timeout--));
	
	if(timeout <= 0)
	{
		rt_kprintf("i2c_master_recv() timeout waits until the I2C bus is recv\n");
		rt_mutex_release(mutex);
		
		i2c_stop_on_bus(i2c_periph);
		/* disable the error interrupt */
		i2c_interrupt_disable(i2c_periph, I2C_INT_ERR);
		i2c_interrupt_disable(i2c_periph, I2C_INT_EV);
		i2c_interrupt_disable(i2c_periph, I2C_INT_BUF);
		
		return -1;
	}
	
	if(pdata->status != 0)
	{
		//rt_kprintf("i2c_master_recv() error status=%08X\n", pdata->status);
		
		i2c_stop_on_bus(i2c_periph);
		/* disable the error interrupt */
		i2c_interrupt_disable(i2c_periph, I2C_INT_ERR);
		i2c_interrupt_disable(i2c_periph, I2C_INT_EV);
		i2c_interrupt_disable(i2c_periph, I2C_INT_BUF);
		
		rt_mutex_release(mutex);
		return -1;
	}
	
	memcpy(buf, (void *)&pdata->rxbuf[0], len);
	
	rt_mutex_release(mutex);
	return 0;
}

/*-----------------------------------------------------------------------------
** PROC NAME	: i2c_slave_send

** DESCRIPTION	: send data in slave transmit mode

** PARAMETERS	: i2c_periph - I2Cx(x=0,1,2)
**                slave_addr - i2cx slace address
**                buf - data to transmit
**                len - data length to transmit

** RETURN       : 0 - success, -1 - fail.

** NOTES:
**----------------------------------------------------------------------------*/
int i2c_slave_send(uint32_t i2c_periph, uint8_t slave_addr, uint8_t *buf, uint32_t len)
{
	I2CX_INTERRUPT_DATA *pdata;
//	int timeout = 100000;
	rt_mutex_t mutex;
	
	if(i2c_periph == I2C0)
	{
		pdata = &i2c0_data;
		mutex = i2c0_mutex;
	}
	else if(i2c_periph == I2C1)
	{
		pdata = &i2c1_data;
		mutex = i2c1_mutex;
	}
	else
	{
		rt_kprintf("i2c_periph not support. I2Cx(x=0,1,2).\n");
		return -1;
	}
	
	if(rt_mutex_take(mutex , RT_WAITING_FOREVER) != RT_EOK)
	{
		rt_kprintf("i2c_slave_send() rt_mutex_take return error.\n");
		return -1;
	}
	
	i2c_reset_tx_data(i2c_periph);
	
//	pdata->addr = slave_addr;
	pdata->master = I2C_SLAVE_CH;
	pdata->send = 0;
	memcpy((void *)&pdata->txbuf[0], buf, len);
	pdata->txcount = len;
	
	/* enable the I2Cx interrupt */
    i2c_interrupt_enable(i2c_periph, I2C_INT_ERR);
    i2c_interrupt_enable(i2c_periph, I2C_INT_BUF);
    i2c_interrupt_enable(i2c_periph, I2C_INT_EV);
	
//	while(pdata->txdone == 0);
	
//	if(pdata->status != 0)
//	{
//	   rt_kprintf("i2c_slave_send() error status=%08X\n", pdata->status);
//	   return -1;
//	}

	rt_mutex_release(mutex);
	return 0;
}

/*-----------------------------------------------------------------------------
** PROC NAME	: i2c_slave_recv

** DESCRIPTION	: receive data in slave receive mode

** PARAMETERS	: i2c_periph - I2Cx(x=0,1,2)
**                slave_addr - i2cx slace address
**                buf - data to receive
**                len - data length to receive

** RETURN       : 0 - success, -1 - fail.

** NOTES:
**----------------------------------------------------------------------------*/
int i2c_slave_recv(uint32_t i2c_periph, uint8_t slave_addr, uint8_t *buf, uint32_t *len)
{
	I2CX_INTERRUPT_DATA *pdata;
//	int timeout = 100000;
	rt_mutex_t mutex;
	
	if(i2c_periph == I2C0)
	{
		pdata = &i2c0_data;
		mutex = i2c0_mutex;
	}
	else if(i2c_periph == I2C1)
	{
		pdata = &i2c1_data;
		mutex = i2c1_mutex;
	}
	else
	{
		rt_kprintf("i2c_periph not support. I2Cx(x=0,1,2).\n");
		return -1;
	}
	
	if(rt_mutex_take(mutex , RT_WAITING_FOREVER) != RT_EOK)
	{
		rt_kprintf("i2c_slave_recv() rt_mutex_take return error.\n");
		return -1;
	}
	
	i2c_reset_rx_data(i2c_periph);
	
//	pdata->addr = slave_addr;
	pdata->master = I2C_MASTER_CH;
	pdata->send = 0;
	pdata->rxcount = 128;
	
	/* enable the I2Cx interrupt */
    i2c_interrupt_enable(i2c_periph, I2C_INT_ERR);
    i2c_interrupt_enable(i2c_periph, I2C_INT_BUF);
    i2c_interrupt_enable(i2c_periph, I2C_INT_EV);
	
	while((pdata->rxdone == 0) && (pdata->status == 0));
	
	if(pdata->status != 0)
	{
		rt_kprintf("i2c_slave_recv() error status=%08X\n", pdata->status);
		rt_mutex_release(mutex);
		return -1;
	}
	
	*len = pdata->rxindex;
	memcpy(buf, (void *)&pdata->rxbuf[0], *len);
	
	rt_mutex_release(mutex);
	return 0;
}


/*!
    \brief      this function handles I2C0 event interrupt request exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void I2C0_EV_IRQHandler(void)
{
    I2C0_EventIRQ_Handler();
}

/*!
    \brief      this function handles I2C0 error interrupt request exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void I2C0_ER_IRQHandler(void)
{
    I2C0_ErrorIRQ_Handler();
}

/*!
    \brief      this function handles I2C1 event interrupt request exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void I2C1_EV_IRQHandler(void)
{
    I2C1_EventIRQ_Handler();
}

/*!
    \brief      this function handles I2C1 error interrupt request exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void I2C1_ER_IRQHandler(void)
{
    I2C1_ErrorIRQ_Handler();
}

/*!
    \brief      this function handles RTC global interrupt request
    \param[in]  none
    \param[out] none
    \retval     none
*/


/////////////////////////////////////////////////// shell command ///////////////////////////////////////////////////


int cmd_i2c_master_send(int argc, char **argv)
{
	int i2c_periph, slave_addr, len;
	if(argc != 5)
	{
		rt_kprintf("usetage:	i2c_master_send(uint32_t i2c_periph, uint8_t slave_addr, uint8_t *buf, uint32_t len)\n");
		rt_kprintf("	i2c_master_send [0|1] [0x82] \"1234567890\" 10\n");
		return -1;
	}
	
	i2c_periph = atoi(argv[1]);
	slave_addr = (argv[2][2]-0x30)*16 + (argv[2][3]-0x30);//atoi(argv[2]); 
	len = atoi(argv[4]);
	
	printf("i2c_periph=%d, slave_addr=%02x, len=%d\n", i2c_periph, slave_addr, len);
	
	return i2c_master_send(I2Cx[i2c_periph], slave_addr, (uint8_t *)argv[3], len);
}
FINSH_FUNCTION_EXPORT_ALIAS(cmd_i2c_master_send, __cmd_i2c_master_send, i2c master send.);


int cmd_i2c_master_recv(int argc, char **argv)
{
	int i2c_periph, slave_addr, len;
	int ret;
	uint8_t rxbuf[256];
	
	if(argc != 4)
	{
		rt_kprintf("usetage:	i2c_master_recv(uint32_t i2c_periph, uint8_t slave_addr, uint32_t len)\n");
		rt_kprintf("	i2c_master_recv [0|1] [0x82] [10]\n");
		return -1;
	}
	
	i2c_periph = atoi(argv[1]);
	slave_addr = (argv[2][2]-0x30)*16 + (argv[2][3]-0x30);//atoi(argv[2]);
	len = atoi(argv[3]);
	
	printf("i2c_periph=%d, slave_addr=%02x, len=%d\n", i2c_periph, slave_addr, len);
	
	ret = i2c_master_recv(I2Cx[i2c_periph], slave_addr, rxbuf, len);
	if(ret != -1)
	{
		for(int i=0; i<len; i++)
		{
			rt_kprintf("%02x ", rxbuf[i]);
		}
		rt_kprintf("\n");
	}
	
	return ret;
}
FINSH_FUNCTION_EXPORT_ALIAS(cmd_i2c_master_recv, __cmd_i2c_master_recv, i2c master recv.);


int cmd_i2c_slave_send(int argc, char **argv)
{
	int i2c_periph, slave_addr, len;
	if(argc != 5)
	{
		rt_kprintf("usetage:	int i2c_slave_send(uint32_t i2c_periph, uint8_t slave_addr, uint8_t *buf, uint32_t len)\n");
		rt_kprintf("	i2c_slave_send [0|1] [0x82] \"1234567890\" 10\n");
		return -1;
	}
	
	i2c_periph = atoi(argv[1]);
	slave_addr = (argv[2][2]-0x30)*16 + (argv[2][3]-0x30);//atoi(argv[2]);
	len = atoi(argv[4]);
	
	printf("i2c_periph=%d, slave_addr=%02x, len=%d\n", i2c_periph, slave_addr, len);
	
	return i2c_slave_send(I2Cx[i2c_periph], slave_addr, (uint8_t *)argv[3], len);
}
FINSH_FUNCTION_EXPORT_ALIAS(cmd_i2c_slave_send, __cmd_i2c_slave_send, i2c slave send.);


int cmd_i2c_slave_recv(int argc, char **argv)
{
	int i2c_periph, slave_addr, len;
	int ret;
	uint8_t rxbuf[256];
	
	if(argc != 3)
	{
		rt_kprintf("usetage:	int i2c_slave_recv(uint32_t i2c_periph, uint8_t slave_addr)\n");
		rt_kprintf("	i2c_slave_recv [0|1] [0x82]\n");
		return -1;
	}
	
	i2c_periph = atoi(argv[1]);
	slave_addr = (argv[2][2]-0x30)*16 + (argv[2][3]-0x30);//atoi(argv[2]);
	//len = atoi(argv[3]);
	
	printf("i2c_periph=%d, slave_addr=%02x\n", i2c_periph, slave_addr);
	
	ret = i2c_slave_recv(I2Cx[i2c_periph], slave_addr, rxbuf, (uint32_t *)&len);
	if(ret != -1)
	{
		for(int i=0; i<len; i++)
		{
			rt_kprintf("%02x ", rxbuf[i]);
		}
		rt_kprintf("\n");
	}
	
	return ret;
}
FINSH_FUNCTION_EXPORT_ALIAS(cmd_i2c_slave_recv, __cmd_i2c_slave_recv, i2c slave recv.);

